/**
 * @file
 * video decoding with libavcodec API example
 *
 * @example decode_video.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/avutil.h>
#include <libavcodec/codec_id.h>
#include <libavcodec/packet.h>



const char *out_filename = "output.h264";
int main(int argc, char **argv)
{
    //编码器
    const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); //h264编码器
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        return -1;
    }
    //编码上下文 
    AVCodecContext *c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate video codec context\n");
        return -1;

    }
    c->bit_rate = 400000;
    c->width = 640;
    c->height = 480;
    c->time_base = (AVRational ){1, 25}; //分子 分母 1/25 (1/time_base  the average frame rate) 帧率
    c->gop_size = 12;  // the number of pictures in a group of pictures I帧间隔
    c->max_b_frames = 1;  //maximum number of B-frames between non-B-frames 最大B帧数
    // c->pix_fmt = AV_PIX_FMT_UYVY422;       //pixel format ：UYVY
    c->pix_fmt = AV_PIX_FMT_YUV420P;       //pixel format ：UYVY

    if(avcodec_open2(c,codec, NULL) < 0){
        fprintf(stderr, "Could not open codec\n");
        return -1;
    }

    //输出文件及格式上下文
    AVFormatContext *fmt_ctx = NULL;
    if(avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, out_filename) <0){
        fprintf(stderr, "Could not create ouput context\n");
        return -1;
    }

    // 添加视频流到输出上下文
    AVStream *stream = avformat_new_stream(fmt_ctx, codec);
    if(!stream){
        fprintf(stderr, "Could not create stream\n");
        return -1;    
    }
    avcodec_parameters_from_context(stream->codecpar, c);
    
    //打开输出文件
    if(avio_open (&fmt_ctx->pb, out_filename, AVIO_FLAG_WRITE ) < 0){
        fprintf(stderr, "Could not open output file\n");
        return -1;    
    }

    // 写头部信息
    int ret = avformat_write_header(fmt_ctx, NULL); 
    if (ret < 0 ){
        fprintf(stderr, "Could not write header\n");
        return -1;   
    }
    // 准备一帧原始图像数据（这里简化处理，实际应用中可能来自摄像头、文件等）
    AVFrame *frame = av_frame_alloc(); 
    frame->format = c->pix_fmt;
    frame->width = c->width;
    frame->height = c->height;
    if (av_frame_get_buffer(frame, 32) < 0) {  // 添加对齐参数
        fprintf(stderr, "Could not allocate frame buffer\n");
        return -1;
    }

    // 填充YUV数据（示例：灰色背景）
    memset(frame->data[0], 128, frame->linesize[0] * c->height);          // Y
    memset(frame->data[1], 128, frame->linesize[1] * c->height / 2);      // U
    memset(frame->data[2], 128, frame->linesize[2] * c->height / 2);      // V

    // 编码循环
    AVPacket *pkt = av_packet_alloc();
    for (int i = 0; i < 25; i++) {  // 编码25帧
        frame->pts = i;

        // 发送帧到编码器
        if (avcodec_send_frame(c, frame) < 0) {
            fprintf(stderr, "Error sending frame\n");
            break;
        }

        // 接收编码后的包
        while (1) {
            ret = avcodec_receive_packet(c, pkt);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                break;
            else if (ret < 0) {
                fprintf(stderr, "Error during encoding\n");
                break;
            }
            // 写入文件
            av_interleaved_write_frame(fmt_ctx, pkt);
            av_packet_unref(pkt);
        }
    }

    av_write_trailer(fmt_ctx);
    av_packet_free(&pkt);
    av_frame_free(&frame);
    avformat_free_context(fmt_ctx);
    avcodec_free_context(&c);
    return 0;
}


